﻿using System;
using System.Text;
using System.Threading.Tasks;
using SyZero;
using SyZero.Cache;
using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;

namespace SyZero.Redis
{
    public class Cache : ICache
    {
        protected IDistributedCache cache;

        /// <summary>
        /// 通过IDistributedCache来构造RedisCache缓存操作类
        /// </summary>
        /// <param name="cache">IDistributedCache对象</param>
        public Cache(IDistributedCache cache)
        {
            this.cache = cache;
        }

        public bool Exist(string key)
        {
            var bytesObject = cache.Get(key);//从Redis中获取键值key的字节数组，如果没获取到，那么会返回null

            if (bytesObject == null)
            {
                return false;
            }

            return true;
        }

        public T Get<T>(string key, out bool isExisted)
        {
            var bytesObject = cache.Get(key);//从Redis中获取键值key的字节数组，如果没获取到，那么会返回null

            if (bytesObject == null)
            {
                isExisted = false;
                return default(T);
            }

            var stringObject = Encoding.UTF8.GetString(bytesObject);//通过UTF-8编码，将字节数组反序列化为Json字符串

            isExisted = true;

            //通过Json.NET反序列化Json字符串为对象
            //调用JsonConvert.DeserializeObject方法时，也设置TypeNameHandling属性为TypeNameHandling.All，这样可以保证Json.NET在反序列化对象时，去读取Json字符串中的序列化类型，从而得到和序列化时相同的对象类型
            return JsonConvert.DeserializeObject<T>(stringObject, new JsonSerializerSettings()
            {
                TypeNameHandling = TypeNameHandling.All
            });
        }

        public void Refresh(string key)
        {
            cache.Refresh(key);
        }

        public Task RefreshAsync(string key)
        {
            return cache.RefreshAsync(key);
        }

        public void Remove(string key)
        {
            cache.Remove(key);//如果键值在Redis中不存在，IDistributedCache.Remove方法不会报错，但是如果传入的参数key为null，则会抛出异常
        }

        public Task RemoveAsync(string key)
        {
            return cache.RemoveAsync(key);
        }

        public void Set(string key, object value, int exprireTime = 24)
        {
            //通过Json.NET序列化缓存对象为Json字符串
            //调用JsonConvert.SerializeObject方法时，设置ReferenceLoopHandling属性为ReferenceLoopHandling.Ignore，来避免Json.NET序列化对象时，因为对象的循环引用而抛出异常
            //设置TypeNameHandling属性为TypeNameHandling.All，这样Json.NET序列化对象后的Json字符串中，会包含序列化的类型，这样可以保证Json.NET在反序列化对象时，去读取Json字符串中的序列化类型，从而得到和序列化时相同的对象类型
            var stringObject = JsonConvert.SerializeObject(value, new JsonSerializerSettings()
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                TypeNameHandling = TypeNameHandling.All
            });
        
            var bytesObject = Encoding.UTF8.GetBytes(stringObject);//将Json字符串通过UTF-8编码，序列化为字节数组

            cache.Set(key, bytesObject, new DistributedCacheEntryOptions()
                {
                    AbsoluteExpiration = DateTime.Now.AddHours(exprireTime)
                });//将字节数组存入Redis
            Refresh(key);//刷新Redis
        }

        public Task SetAsync(string key, object value, int exprireTime = 24)
        {
            return Task.Run(() => { Set(key, value, exprireTime); });
        }
    }
}
